<?php

/**
 * Object/XCalculator.php
 */

namespace RHX\Model\Object;

use Zend\Db\Adapter\Adapter;
use RHX\Helper\RHDateTime;
use RHX\Model\Object\XData;
use RHX\Model\Object\XRules;
use RHX\Model\Object\PlanningSemaine;
use RHX\Model\Table\PlanningSemaineTable;
use RHX\Model\Object\EmployeTemplate;
use RHX\Model\Table\EmployeTemplateTable;
use RHX\Model\Table\PeriodeTable;
use RHX\Model\Table\PeriodeSemaineTable;
use RHX\Model\Table\EmployeTable;
use RHX\Model\Object\Periode;
use RHX\Helper\Number;

class XCalculator {

    /**
     *
     * @var Adapter $adapter Adapteur de base de données
     */
    protected $adapter;

    /**
     * Constructeur
     *
     * @param \Zend\Db\Adapter\Adapter $adapter
     */
    public function __construct(Adapter $adapter) {
	$this->adapter = $adapter;
    }

    /**
     * Récupérer l'adapteur
     * 
     * @return Adapter
     */
    public function getAdapter() {
	return $this->adapter;
    }

    /**
     * Calcul d'un jour
     * 
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param \RHX\Model\Object\EmployeTemplate $template
     * @param string $prefix
     * @param boolean $hnp Heure Non plannifié
     * @return XData
     */
    public function calculateOneDay(PlanningSemaine $planning, $template, $prefix = 'lundi', $hnp = false) {
	$data = new XData();

	// Préparation des variables dynamiques
	$prefixCode	 = $prefix . '_code';
	$prefixEntree	 = $prefix . '_entree';
	$prefixSortie	 = $prefix . '_sortie';
	$prefixPause	 = $prefix . '_pause';
	$prefixRepas	 = $prefix . '_repas';

	// Assignation et Préparation des variables
	$code	 = (int) $planning->$prefixCode;
	$entree	 = $planning->$prefixEntree;
	$sortie	 = $planning->$prefixSortie;
	$pause	 = (int) $planning->$prefixPause;
	$repas	 = (int) $planning->$prefixRepas;
	$coef	 = floatval($planning->coef);

	// Employé
	$employe = $planning->getEmploye();

	// taux Horaire
	$taux = $employe->getTaux($planning->$prefix);

	// Traitement du Coefficient
	if ($coef == 0) {
	    $coef = $employe->getCoefficient();
	}

	// Test des Données
	switch ($code) {
	    case XRules::Present:
		// Tous les calculs sauf les retards
		$data		 = $this->calculPresent($entree, $sortie, $pause, $repas, $coef, $taux);
		break;
	    case XRules::ProblemeRetardDepartAnticipe:
		// Tous les calculs avec les retards
		$reference	 = $this->getTimeReference($planning, $prefix);
		$data		 = $this->calculPRDA($entree, $sortie, $pause, $repas, $coef, $taux, $reference['entree'], $reference['sortie']);
		if ($hnp) {
		    $data = $this->calculPresent($reference['entree'], $reference['sortie'], $pause, $repas, $coef, $taux);
		}
		break;
	    case XRules::CongePaye:
		// Calcul des jours de disponibilités
		// Pas de pause et pas de repas
		$hebdo	 = $employe->getHoraireHebdo(false, $planning->$prefix);
		$dispo	 = $employe->getNbJourDispo(true);
		$data	 = $this->calculCongePaye($coef, $taux, $hebdo, $dispo);
		if (!$hnp) {
		    $data->tempsDiff = '00:00';
		}
		break;
	    case XRules::NeTravaillePas:
		// pas de repas, pas de pause
		break;
	    case XRules::Absent:
		// L'absence est compté comme retard mais les heures ne sont pas décompté
		// Avec pause et pas de repas
		$data->retard		 = true;
		$dataNormal		 = $this->calculPresent($entree, $sortie, $pause, 0, $coef, $taux);
		$data->tempsRetard	 = $dataNormal->tempsDiff;
		break;
	    case XRules::AccidentTravail:
		// On laisse les heures du planning
		// mais pas de repas, pas de pause
		$data			 = $this->calculPresent($entree, $sortie, 0, 0, $coef, $taux);
		break;
	    case XRules::ArretMaladie1:
		// Les 3 premiers jours les horaires sont décomptés mais pas payés
		$data			 = $this->calculPresent($entree, $sortie, $pause, 0, $coef, $taux);
		$data->montant		 = 0.0; // Pas Payés
//		if (!$hnp) {
//		    $data->tempsDiff = '00:00';
//		}
		$data->tempsDiff = '00:00';
		break;
	    case XRules::ArretMaladie2:
		// Payé par la société
		$data		 = $this->calculPresent($entree, $sortie, $pause, 0, $coef, $taux);
		$employe	 = $planning->getEmploye();
		$anciennete	 = $employe->getAncienneteValue();
		if ($anciennete < 1) {
		    $data->montant = 0.0; // N'est pas payés
		}
		if (!$hnp) {
		    $data->tempsDiff = '00:00';
		}
		break;
	    case XRules::CongeMaternite:
		// Comme les congés Payés
		// Pas de Pause et pas de repas
		$hebdo	 = $employe->getHoraireHebdo(false, $planning->$prefix);
		$dispo	 = $employe->getNbJourDispo(true);
		$data	 = $this->calculCongePaye($coef, $taux, $hebdo, $dispo);
		if (!$hnp) {
		    $data->tempsDiff = '00:00';
		}
		break;
	    case XRules::CongeMaternitePere:
		// Comme les congés payés
		// Pas de Pause et pas de repas
		$hebdo	 = $employe->getHoraireHebdo(false, $planning->$prefix);
		$dispo	 = $employe->getNbJourDispo(true);
		$data	 = $this->calculCongePaye($coef, $taux, $hebdo, $dispo);
		if (!$hnp) {
		    $data->tempsDiff = '00:00';
		}
		break;
	    case XRules::CongePayeExceptionnel:
		// Comme les congés payés
		// Pas de Pause et pas de repas
		$hebdo	 = $employe->getHoraireHebdo(false, $planning->$prefix);
		$dispo	 = $employe->getNbJourDispo(true);
		$data	 = $this->calculCongePaye($coef, $taux, $hebdo, $dispo);
		if (!$hnp) {
		    $data->tempsDiff = '00:00';
		}
		break;
	    case XRules::CongeSansSolde:
		$data		 = $this->calculPresent($entree, $sortie, $pause, $repas, $coef, $taux);
		if (!$hnp) {
		    $data->tempsDiff = '00:00';
		}
		break;
	    case XRules::EcoleFormationIntegration:
		// Horaire obligatoire 08:00 à 15:30 pause et repas
		$data	 = $this->calculPresent($entree, $sortie, $pause, $repas, $coef, $taux);
		break;
	    case XRules::EcoleFormationAlternance:
		// Alternance 3 jour travail, 2 jour ecoles : pas de pause, pas de repas
		$data	 = $this->calculPresent($entree, $sortie, 0, 0, $coef, $taux);
		break;
	    case XRules::EcoleFormationEmploye:
		// Horaire normal
		$data	 = $this->calculPresent($entree, $sortie, $pause, $repas, $coef, $taux);
		break;
	    case XRules::Ferie1:
		// Comme les congés payés pour les plus d'un an d'ancienneté
		/* $hebdo			 = $employe->getHoraireHebdo(false, $planning->$prefix);
		  $dispo			 = $employe->getNbJourDispo(true);
		  $data			 = $this->calculCongePaye($coef, $taux, $hebdo, $dispo); */
		$data	 = $this->calculPresent($entree, $sortie, $pause, $repas, $coef, $taux);
		if (!$hnp) {
		    $data->tempsDiff = '00:00';
		}
		break;
	    case XRules::Ferie2:
		// Pour les Travailleurs qui ont plus 1 an d'ancienneté, il sont payé Double
		$data = $this->calculPresent($entree, $sortie, $pause, $repas, $coef, $taux * 2);
		if (!$hnp) {
		    $data->tempsDiff = '00:00';
		}
		break;
	    case XRules::Ferie3:
		// Pour les travailleur moins 1 an ancienneté et qui travaille un jour ferié : payé simple
		$data	 = $this->calculPresent($entree, $sortie, $pause, $repas, $coef, $taux);
		break;
	    case XRules::Fermer:
		// On ne fait rien
		break;
	    case XRules::Indisponible:
		// On ne fait rien
		break;
	    case XRules::TransfertEntrant:
		// Ce n'est pas ici que l'on calcul les transferts
		break;
	    case XRules::TransfertSortant:
		// Ce n'est pas ici que l'on calcul les transferts
		// Maintentant c'est ici
		$data	 = $this->calculPresent($entree, $sortie, $pause, $repas, $coef, $taux);
		break;
	    case XRules::Inconnue:
	    default:
		// On ne fait rien
		break;
	}

	return $data;
    }

    /**
     * Calcul des Présences
     *
     * @param int $code
     * @param string $entree
     * @param string $sortie
     * @param int $pause
     * @param int $repas
     * @param float $coef
     * @param float $taux
     * @param array $param
     * @return \RHX\Model\Object\XData
     */
    public function calculPresent($entree, $sortie, $pause, $repas, $coef, $taux, $param = array()) {
	$data = new XData();

	$pauseParam = $pause;

	$pause = $this->getPause($pause);

	$diff	 = RHDateTime::diffHours($sortie, $entree);
	$diff	 = RHDateTime::diffHours($diff, $pause);

	$data->tempsDiff	 = $diff;
	$data->tempsValeur	 = RHDateTime::toFloat($data->tempsDiff);

	$data->montant = $data->tempsValeur * $taux * $coef;

	// Debug
	//$this->Debug("Calcul Normal ($entree, $sortie, $pauseParam, $repas, $coef, $taux) => " . $data->tempsValeur . " x $taux x $coef = " . $data->montant);

	return $data;
    }

    /**
     * Calcul lors des Retards ou Départ anticipé
     *
     * @param string $entree
     * @param string $sortie
     * @param int $pause
     * @param int $repas
     * @param float $coef
     * @param float $taux
     * @param string $refEntree
     * @param string $refSortie
     * @return \RHX\Model\Object\XData
     */
    private function calculPRDA($entree, $sortie, $pause, $repas, $coef, $taux, $refEntree, $refSortie) {
	$data = new XData();

	// Retard
	$tpsRetard = RHDateTime::diffHours($refEntree, $entree);
	if (RHDateTime::toFloat($tpsRetard) > 0) {
	    $data->retard		 = true;
	    $data->tempsRetard	 = $tpsRetard;
	}

	// Départ Anticipé
	$tpsDepartAnticipe = RHDateTime::diffHours($refSortie, $sortie, true, false);
	if (RHDateTime::toFloat($tpsDepartAnticipe) > 0) {
	    $data->anticipe		 = true;
	    $data->tempsAnticipe	 = $tpsDepartAnticipe;
	}

	// Données Normal : Présent
	$dataNormal = $this->calculPresent($entree, $sortie, $pause, $repas, $coef, $taux);

	// Assignation des données
	$data->tempsDiff	 = $dataNormal->tempsDiff;
	$data->tempsValeur	 = $dataNormal->tempsValeur;
	$data->montant		 = $dataNormal->montant;

	return $data;
    }

    /**
     * Calcul pour les Congés Payés
     *
     * @param float $coef
     * @param float $taux
     * @param float $hebdo
     * @param int $dispo
     * @return \RHX\Model\Object\XData
     */
    private function calculCongePaye($coef, $taux, $hebdo, $dispo) {
	$data = new XData();

	$cpValue		 = $this->getCPValue($hebdo, $dispo);
	$data->tempsDiff	 = RHDateTime::toTime(number_format($cpValue, 2, ',', ''));
	$data->tempsValeur	 = $cpValue;
	$data->montant		 = $data->tempsValeur * $taux * $coef;

	return $data;
    }

    /**
     * Temps de Pause
     *
     * @param int $pause
     * @return string
     */
    private function getPause($pause) {
	if ($pause == 1) {
	    return '00:30';
	}

	return '00:00';
    }

    /**
     * Nombre d'heure à décompter pour un Congé Payé
     *
     * @param float $hebdo
     * @param int $dispo
     * @return float
     */
    private function getCPValue($hebdo, $dispo) {
	$value = number_format($hebdo / $dispo, 2);

	return floatval($value);
    }

    /**
     * Total des Heures semaines
     *
     * @param \RHX\Model\Object\XData $dataLundi
     * @param \RHX\Model\Object\XData $dataMardi
     * @param \RHX\Model\Object\XData $dataMercredi
     * @param \RHX\Model\Object\XData $dataJeudi
     * @param \RHX\Model\Object\XData $dataVendredi
     * @param \RHX\Model\Object\XData $dataSamedi
     * @param \RHX\Model\Object\XData $dataDimanche
     * @return array
     */
    public function calculateWeek(XData $dataLundi, XData $dataMardi, XData $dataMercredi, XData $dataJeudi, XData $dataVendredi, XData $dataSamedi, XData $dataDimanche) {
	// Total des heures Travaillé
	$heureTravaille = new RHDateTime();
	$heureTravaille->setTime();
	$heureTravaille->addHours($dataLundi->tempsDiff, false);
	$heureTravaille->addHours($dataMardi->tempsDiff, false);
	$heureTravaille->addHours($dataMercredi->tempsDiff, false);
	$heureTravaille->addHours($dataJeudi->tempsDiff, false);
	$heureTravaille->addHours($dataVendredi->tempsDiff, false);
	$heureTravaille->addHours($dataSamedi->tempsDiff, false);
	$heureTravaille->addHours($dataDimanche->tempsDiff, false);

	// Total des heures de retard
	$heurePRDA	 = new RHDateTime();
	$heurePRDA->setTime();
	$nbPRDA		 = 0;

	// Lundi
	if ($dataLundi->retard) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataLundi->tempsRetard, false);
	}
	if ($dataLundi->anticipe) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataLundi->tempsAnticipe, false);
	}

	// Mardi
	if ($dataMardi->retard) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataMardi->tempsRetard, false);
	}
	if ($dataMardi->anticipe) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataMardi->tempsAnticipe, false);
	}

	// Mercredi
	if ($dataMercredi->retard) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataMercredi->tempsRetard, false);
	}
	if ($dataMercredi->anticipe) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataMercredi->tempsAnticipe, false);
	}

	// Jeudi
	if ($dataJeudi->retard) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataJeudi->tempsRetard, false);
	}
	if ($dataJeudi->anticipe) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataJeudi->tempsAnticipe, false);
	}

	// Vendredi
	if ($dataVendredi->retard) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataVendredi->tempsRetard, false);
	}
	if ($dataVendredi->anticipe) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataVendredi->tempsAnticipe, false);
	}

	// Samedi
	if ($dataSamedi->retard) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataSamedi->tempsRetard, false);
	}
	if ($dataSamedi->anticipe) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataSamedi->tempsAnticipe, false);
	}

	// Dimanche
	if ($dataDimanche->retard) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataDimanche->tempsRetard, false);
	}
	if ($dataDimanche->anticipe) {
	    $nbPRDA++;
	    $heurePRDA->addHours($dataDimanche->tempsAnticipe, false);
	}

	return array(
	    'heureTravaille' => $heureTravaille->totalHours(),
	    'nbPRDA'	 => $nbPRDA,
	    'heurePRDA'	 => $heurePRDA->totalHours(),
	);
    }

    /**
     * Récupérer les heures non plannifié
     *
     * @param int $matricule
     * @param string $date
     * @return array
     */
    public function getHeureNonPlannifie($matricule, $date) {
	// Periode Table
	$periodeTable = new PeriodeTable($this->getAdapter());

	// Période en cours
	$periodeData		 = $periodeTable->getPeriodeByDate($date);
	$periode		 = new Periode($periodeData);
//	\Zend\Debug\Debug::dump($periode, "Période en cours");
	// Table semaine
	$tableSemaine		 = new \RHX\Model\Table\SemaineTable($this->getAdapter());
	$semaine		 = $tableSemaine->getSemaineByDate($date);
	//\Zend\Debug\Debug::dump($semaine, "Semaine de référence");
	//$semaine	 = new Semaine($semaineData);
	// table Periode Semaine
	$tablePeriodeSemaine	 = new PeriodeSemaineTable($this->getAdapter());
	$semaineList		 = $tablePeriodeSemaine->getSemainesListByPeriode($periode->id, $semaine->id);
//	\Zend\Debug\Debug::dump($semaineList, "Liste des semaines");
	// table planning Semaine
	$tablePlanning		 = new PlanningSemaineTable($this->getAdapter());

	$totalHNP	 = new RHDateTime();
	$totalHNP->setTime();
	$totalHT	 = new RHDateTime();
	$totalHT->setTime();
	$totalHP	 = new RHDateTime();
	$totalHT->setTime();
	$nb		 = 0;
	$signe		 = 0.0;
	$tableEmploye	 = new EmployeTable($this->getAdapter());
	foreach ($semaineList as $sem) {
	    //\Zend\Debug\Debug::dump($sem, "Semaine à calculer");
	    try {
//	    \Zend\Debug\Debug::dump($sem, 'Semaine ' . ($nb + 1));
		$planning	 = $tablePlanning->getPlanningByDay($sem->lundi, $matricule);
		$planningManager = new \RHX\Model\Manager\PlanningManager($this->getAdapter());
//		\Zend\Debug\Debug::dump($planning, 'Planning ' . ($nb + 1));
		if ($planning) {
		    $template	 = $planning->getTemplate();
		    $dataLundi	 = $this->calculateOneDay($planning, $template, 'lundi', true);
		    $dataMardi	 = $this->calculateOneDay($planning, $template, 'mardi', true);
		    $dataMercredi	 = $this->calculateOneDay($planning, $template, 'mercredi', true);
		    $dataJeudi	 = $this->calculateOneDay($planning, $template, 'jeudi', true);
		    $dataVendredi	 = $this->calculateOneDay($planning, $template, 'vendredi', true);
		    $dataSamedi	 = $this->calculateOneDay($planning, $template, 'samedi', true);
		    $dataDimanche	 = $this->calculateOneDay($planning, $template, 'dimanche', true);
		    $dataWeek	 = $this->calculateWeek($dataLundi, $dataMardi, $dataMercredi, $dataJeudi, $dataVendredi, $dataSamedi, $dataDimanche);
		    //$heurePrevues		 = $planning->heure_prevues;
		    $employe	 = $tableEmploye->get($planning->matricule);
		    $hebdo		 = $employe->getHoraireHebdo(false, $date);
		    $stats		 = $planningManager->getWeekStat($planning);
		    $codes		 = $stats['codes'];
		    $heurePrevues	 = '00:00';
		    //\Zend\Debug\Debug::dump($stats);
		    if (isset($codes[XRules::EntreeSortie])) {
			$dayName	 = array(1 => 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche');
			$heurePrevues	 = $this->prorataHeurePrevues(RHDateTime::toTime($hebdo), $dayName[$codes[XRules::EntreeSortie]]);
			$heurePrevues	 = $heurePrevues['time'];
		    }
		    else {
			$heurePrevues = RHDateTime::toTime($hebdo);
		    }
		    $heureTravailles	 = $dataWeek['heureTravaille'];
		    // $heureNonPlanifie	 = RHDateTime::diffHours($heurePrevues, $heureTravailles, false);
		    $heureNonPlanifie	 = RHDateTime::diffHours($heurePrevues, $heureTravailles, false);
		    $floatVal		 = RHDateTime::toFloat($heureTravailles) - RHDateTime::toFloat($heurePrevues);
		    $signe += $floatVal;
//		    echo '<pre>Heure Non Planifie : ' .$heureNonPlanifie .'</pre>';
//		    echo '<pre>Heure Travaille : ' .$heureTravailles .'</pre>';
//		    echo '<pre>Heure Prevues : ' .$heurePrevues .'</pre>';
//		    echo '<pre>Valeur' .$floatVal .'</pre>';
		    $totalHNP->addHours($heureNonPlanifie, false);
		    $totalHT->addHours($heureTravailles, false);
		    $totalHP->addHours($heurePrevues, false);
		    $nb++;
		}
	    }
	    catch (\Exception $ex) {
		continue;
	    }
	}

	return array(
	    //'heureNonPlanifie'	 => ($signe < 0) ? '-' . Number::frenchFormat(RHDateTime::toFloat($totalHNP->totalHours())) : Number::frenchFormat(RHDateTime::toFloat($totalHNP->totalHours())),
	    'heureNonPlanifie'	 => Number::frenchFormat($signe),
	    'heureTravaille'	 => $totalHT->totalHours(),
	    'heurePrevue'		 => $totalHP->totalHours(),
	    'nb'			 => $nb,
	    'periode'		 => $periode,
	    'count'			 => $semaineList->count(),
	    'semaine'		 => $semaine,
	    'date'			 => $date,
	    'matricule'		 => $matricule,
	    'signe'			 => $signe,
	);
    }

    /**
     * Mise à jour des heures travaillées
     * Mise à jour des heures non planifiées
     * 
     * @param \RHX\Model\Object\PlanningSemaine $pl
     * @param \RHX\Model\Table\PlanningSemaineTable $tablePlanning
     * @return int
     */
    public function updateHeureTravail(PlanningSemaine $pl, PlanningSemaineTable $tablePlanning) {
	$travail	 = new RHDateTime();
	$travail->setTime('00:00');
	$dayNames	 = array(
	    'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche',
	);
	foreach ($dayNames as $day) {
	    $data = $this->calculateOneDay($pl, $pl->getTemplate(), $day);
	    $travail->addHours($data->tempsDiff, false);
	}
	// Enregistrement dans la base de données
	$pl->heure_travail	 = $travail->totalHours();
	// Heures non plannifiés
	$heurePlanifie		 = new RHDateTime();
	$heurePlanifie->setTime($pl->heure_prevues);
	$floatTravail		 = RHDateTime::toFloat($travail->totalHours());
	$floatPrevue		 = RHDateTime::toFloat($pl->heure_prevues);
	$signe			 = ($floatPrevue > $floatTravail) ? '-' : '';
	$diff			 = RHDateTime::diffHours($travail->totalHours(), $pl->heure_prevues, false);
	$pl->heure_non_planifie	 = $signe . RHDateTime::toFloat($diff);

	return $tablePlanning->save($pl);
    }

    /**
     * Calcul d'une semaine
     * 
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param \RHX\Model\Object\EmployeTemplate $template
     * @param string $date
     * @return array
     */
    public function calculateOneWeek(PlanningSemaine $planning, $template, $date) {
	// Calcul de la semaine
	$dataLundi	 = $this->calculateOneDay($planning, $template, 'lundi');
	$dataMardi	 = $this->calculateOneDay($planning, $template, 'mardi');
	$dataMercredi	 = $this->calculateOneDay($planning, $template, 'mercredi');
	$dataJeudi	 = $this->calculateOneDay($planning, $template, 'jeudi');
	$dataVendredi	 = $this->calculateOneDay($planning, $template, 'vendredi');
	$dataSamedi	 = $this->calculateOneDay($planning, $template, 'samedi');
	$dataDimanche	 = $this->calculateOneDay($planning, $template, 'dimanche');
	$dataWeek	 = $this->calculateWeek($dataLundi, $dataMardi, $dataMercredi, $dataJeudi, $dataVendredi, $dataSamedi, $dataDimanche);
	// Nom du jour
	$dayName	 = ucfirst(RHDateTime::dayName($date));
	$variable	 = "data$dayName";
	$dataWeek['day'] = $$variable;

	return $dataWeek;
    }

    /**
     * Récupérer les références de temps
     *
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param string $prefix
     * @return array
     */
    public function getTimeReference(PlanningSemaine $planning, $prefix = 'lundi', $heureDefaut = '08:00') {
	$reference	 = array();
	$prefixEntree	 = $prefix . '_entree_ref';
	$prefixSortie	 = $prefix . '_sortie_ref';
	$entree		 = RHDateTime::hourNoSecond($planning->$prefixEntree);
	$sortie		 = RHDateTime::hourNoSecond($planning->$prefixSortie);
	if ($entree == '00:00' || $entree == '00:00:00' || $sortie == '00:00' || $sortie == '00:00:00') {
	    // On regarde dans les plannings type
	    $template	 = $planning->getTemplate();
	    $prefixEntree	 = $prefix . '_entree';
	    $prefixSortie	 = $prefix . '_sortie';
	    $entree		 = RHDateTime::hourNoSecond($template->$prefixEntree);
	    $sortie		 = RHDateTime::hourNoSecond($template->$prefixSortie);
	    if ($entree == '00:00' || $entree == '00:00:00' || $sortie == '00:00' || $sortie == '00:00:00') {
		// On invente une heure
		// Employe
		$employe = $planning->getEmploye();
		$cp	 = $employe->getDataCP();
		$fin	 = new RHDateTime($heureDefaut);
		$fin->addHours($cp['heure']);
		$entree	 = $heureDefaut;
		$sortie	 = $fin->hours();
	    }
	}

	$reference['entree']	 = $entree;
	$reference['sortie']	 = $sortie;
	//var_dump($reference);

	return $reference;
    }

    /**
     * Calcul d'un jour pour les Synthèse
     *
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param string $prefix
     * @return XData
     */
    public function calculateOneDayForSynthese(PlanningSemaine $planning, $prefix = 'lundi') {
	$data = new XData();

	// Préparation des variables dynamiques
	$prefixCode	 = $prefix . '_code';
	$prefixEntree	 = $prefix . '_entree';
	$prefixSortie	 = $prefix . '_sortie';
	$prefixPause	 = $prefix . '_pause';
	$prefixRepas	 = $prefix . '_repas';

	// Assignation et Préparation des variables
	$code	 = (int) $planning->$prefixCode;
	$entree	 = $planning->$prefixEntree;
	$sortie	 = $planning->$prefixSortie;
	$pause	 = (int) $planning->$prefixPause;
	$repas	 = (int) $planning->$prefixRepas;
	$coef	 = floatval($planning->coef);

	// Employé
	$employe = $planning->getEmploye();

	// taux Horaire
	$taux = $employe->getTaux($planning->$prefix);

	// Traitement du Coefficient
	if ($coef == 0) {
	    $coef = $employe->getCoefficient();
	}

	// Test des Données
	switch ($code) {
	    case XRules::Present:
		// Tous les calculs sauf les retards
		$data		 = $this->calculPresent($entree, $sortie, $pause, $repas, $coef, $taux);
		break;
	    case XRules::ProblemeRetardDepartAnticipe:
		// Tous les calculs avec les retards
		$reference	 = $this->getTimeReference($planning, $prefix);
		$data		 = $this->calculPRDA($entree, $sortie, $pause, $repas, $coef, $taux, $reference['entree'], $reference['sortie']);
		break;
	    case XRules::CongePaye:
		// N'est pas pris en charge dans les calculs de temps passé sur site
		break;
	    case XRules::NeTravaillePas:
		// pas de repas, pas de pause
		break;
	    case XRules::Absent:
		// N'est pas pris en charge dans les calculs de temps passé sur site
		break;
	    case XRules::AccidentTravail:
		// N'est pas pris en charge dans les calculs de temps passé sur site
		break;
	    case XRules::ArretMaladie1:
		// N'est pas pris en charge dans les calculs de temps passé sur site
		break;
	    case XRules::ArretMaladie2:
		// N'est pas pris en charge dans les calculs de temps passé sur site
		break;
	    case XRules::CongeMaternite:
		// N'est pas pris en charge dans les calculs de temps passé sur site
		break;
	    case XRules::CongeMaternitePere:
		// N'est pas pris en charge dans les calculs de temps passé sur site
		break;
	    case XRules::CongePayeExceptionnel:
		// N'est pas pris en charge dans les calculs de temps passé sur site
		break;
	    case XRules::CongeSansSolde:
		// On ne fait rien
		break;
	    case XRules::EcoleFormationIntegration:
		// N'est pas pris en charge dans les calculs de temps passé sur site
		break;
	    case XRules::EcoleFormationAlternance:
		// Alternance 3 jour travail, 2 jour ecoles : pas de pause, pas de repas
		$data		 = $this->calculPresent($entree, $sortie, 0, 0, $coef, $taux);
		break;
	    case XRules::EcoleFormationEmploye:
		// Horaire normal
		$data		 = $this->calculPresent($entree, $sortie, $pause, $repas, $coef, $taux);
		break;
	    case XRules::Ferie1:
		// N'est pas pris en charge dans les calculs de temps passé sur site
		break;
	    case XRules::Ferie2:
		// Pour les Travailleurs qui ont plus 1 an d'ancienneté, il sont payé Double
		$data		 = $this->calculPresent($entree, $sortie, $pause, $repas, $coef, $taux * 2);
		break;
	    case XRules::Ferie3:
		// Pour les travailleur moins 1 an ancienneté et qui travaille un jour ferié : payé simple
		$data		 = $this->calculPresent($entree, $sortie, $pause, $repas, $coef, $taux);
		break;
	    case XRules::Fermer:
		// On ne fait rien
		break;
	    case XRules::Indisponible:
		// On ne fait rien
		break;
	    case XRules::TransfertEntrant:
		// Ce n'est pas ici que l'on calcul les transferts
		break;
	    case XRules::TransfertSortant:
		// N'est pas pris en charge dans les calculs de temps passé sur site
		break;
	    case XRules::Inconnue:
	    default:
		// On ne fait rien
		break;
	}

	return $data;
    }

    /**
     * Récupération des heures Modulées
     * 
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @return \RHX\Helper\RHDateTime
     */
    public function getHeuresModulees(PlanningSemaine $planning) {
	$days		 = array(
	    'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche',
	);
	$heureModulees	 = new RHDateTime();
	$heureModulees->setTime();
	for ($i = 0; $i < 7; $i++) {
	    $day		 = $days[$i];
	    $dayCode	 = $day . '_code';
	    $dayEntree	 = $day . '_entree';
	    $daySortie	 = $day . '_sortie';
	    $dayPause	 = $day . '_pause';
	    $dayRepas	 = $day . '_repas';
	    $code		 = (int) $planning->$dayCode;
	    $pauseTime	 = '00:30';
	    if ($code == XRules::Present || $code == XRules::ArretMaladie2 || $code == XRules::AccidentTravail || $code == XRules::Ferie1 || $code == XRules::Ferie2 || $code == XRules::TransfertSortant || $code == XRules::ProblemeRetardDepartAnticipe || $code == XRules::EcoleFormationAlternance || $code == XRules::EcoleFormationEmploye || $code == XRules::EcoleFormationIntegration) {
		$diff = RHDateTime::diffHours($planning->$daySortie, $planning->$dayEntree);
		if ((int) $planning->$dayPause == 1) {
		    $diff = RHDateTime::diffHours($diff, $pauseTime);
		}
		$heureModulees->addHours($diff, false);
		//echo "<pre>$diff</pre>";
	    }
	}

	return $heureModulees;
    }

    /**
     * Récupération des Productivités d'une semaine
     * 
     * @param array $plannings
     * @param array $transactions
     * @param int $siteId
     * @return array
     */
    public function getProductivityForOneWeek(Array $plannings, Array $transactions, $siteId) {
	$productivite	 = array(
	    'lundi'		 => 0.0, 'mardi'		 => 0.0, 'mercredi'	 => 0.0, 'jeudi'		 => 0.0, 'vendredi'	 => 0.0, 'samedi'	 => 0.0, 'dimanche'	 => 0.0,
	);
	$heures		 = array(
	    'lundi'		 => new RHDateTime(), 'mardi'		 => new RHDateTime(), 'mercredi'	 => new RHDateTime(), 'jeudi'		 => new RHDateTime(), 'vendredi'	 => new RHDateTime(), 'samedi'	 => new RHDateTime(), 'dimanche'	 => new RHDateTime(),
	);
	foreach ($heures as $heure) {
	    $heure->setTime();
	}

	$days		 = array(
	    'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche',
	);
	$daysOfWeek	 = array();

	// Débogage
	$count = count($plannings);
	//echo "<pre>Il y a $count planning(s)</pre>";
	//return $productivite;

	foreach ($plannings as $planning) {
	    for ($i = 0; $i < 7; $i++) {
		// variables dynamiques
		$day	 = $days[$i];
		$dayCode = $day . '_code';
		$code	 = (int) $planning->$dayCode;
		$data	 = new XData();
		if ($code == XRules::Present || $code == XRules::Ferie2 || $code == XRules::ProblemeRetardDepartAnticipe) {
		    $data = $this->calculateOneDay($planning, $planning->getTemplate(), $day);
		    $heures[$day]->addHours($data->tempsDiff, false);
		    // Débug
		    //echo "<pre>Comptabilisation des heures {$data->tempsDiff}</pre>";
		}
		// jours de la semaine
		if (count($daysOfWeek) < 7) {
		    $daysOfWeek[$day] = $planning->$day;
		}
	    }
	}
	// Transfert entrant
	$tableTransfert	 = new \RHX\Model\Table\TransfertTable($this->getAdapter());
	$pauseTime	 = '00:30';
	for ($i = 0; $i < 7; $i++) {
	    $day		 = $days[$i];
	    $entrants	 = $tableTransfert->getTransfertOfOneDay($daysOfWeek[$day], $siteId, Transfert::Entrant);
	    // Débogage
	    $count		 = $entrants->count();
	    //echo "<pre>Il y a $count Transfert(s) Entrant pour le jour {$daysOfWeek[$day]}</pre>";
	    foreach ($entrants as $entrant) {
		$diff = RHDateTime::diffHours($entrant->sortie, $entrant->entree);
		if ((int) $entrant->pause == 1) {
		    $diff = RHDateTime::diffHours($diff, $pauseTime);
		}
		// Débogage
		//echo "<pre>Comptabilisation des heures $diff</pre>";
		$heures[$day]->addHours($diff, false);
	    }
	}

	// Calcul
	for ($i = 0; $i < 7; $i) {
	    $day		 = $days[$i];
	    $nbTransaction	 = isset($transactions[$day]) ? $transactions[$day] : 0.0;
	    //echo "<pre>$nbTransaction</pre>";
	    if ($nbTransaction == 0) {
		$productivite[$day] += 0;
	    }
	    else {
		$productivite[$day] += $nbTransaction / RHDateTime::toFloat($heures[$day]->totalHours());
	    }
	}

	return $productivite;
    }

    /**
     * Cacul des heures totales
     *
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param \RHX\Model\Object\XData $data
     * @param type $prefix
     * @return \RHX\Helper\RHDateTime
     */
    public function calculHeureTotales(PlanningSemaine $planning, XData $data, $prefix) {
	$heure		 = new RHDateTime();
	$heure->setTime();
	$prefixCode	 = $prefix . '_code';
	$code		 = (int) $planning->$prefixCode;
	if ($code == XRules::Present || $code == XRules::ProblemeRetardDepartAnticipe || $code == XRules::Ferie2 || $code == XRules::EcoleFormationIntegration || $code == XRules::EcoleFormationAlternance || $code == XRules::EcoleFormationEmploye || $code == XRules::CongePaye || $code == XRules::ArretMaladie2 || $code == XRules::AccidentTravail || $code == XRules::CongePayeExceptionnel || $code == XRules::CongeMaternitePere || $code == XRules::Ferie1) {
	    $heure->addHours($data->tempsDiff, false);
//	    echo ($prefix == 'lundi') ? "<pre>Compté pour {$data->tempsDiff}</pre>" : '';
	}
	else {
//	    echo ($prefix == 'lundi') ? "<pre>Non Compté</pre>" : '';
	}

	return $heure;
    }

    /**
     * Calcul des heures travaillées
     * 
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param \RHX\Model\Object\XData $data
     * @param type $prefix
     * @return \RHX\Helper\RHDateTime
     */
    public function calculHeureTravaillees(PlanningSemaine $planning, XData $data, $prefix) {
	$heure		 = new RHDateTime();
	$heure->setTime();
	$prefixCode	 = $prefix . '_code';
	$code		 = (int) $planning->$prefixCode;
	if ($prefix == 'lundi') {
	    //echo "<pre>Code a evaluer : $code</pre>";
	}
	if ($code == XRules::Present || $code == XRules::ProblemeRetardDepartAnticipe || $code == XRules::Ferie2 || $code == XRules::TransfertEntrant) {
	    $heure->addHours($data->tempsDiff, false);
	    if ($prefix == 'lundi') {
		//echo "<pre>Code $code</pre>";
	    }
	}
	/* Il manque plus que les transfert entrants */

	return $heure;
    }

    /**
     * Calcul de la main d'oeuvre total
     * 
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param \RHX\Model\Object\XData $data
     * @param string $prefix
     * @return float
     */
    public function calculMOTotal(PlanningSemaine $planning, XData $data, $prefix) {
	$mo		 = 0.0;
	$prefixCode	 = $prefix . '_code';
	$code		 = (int) $planning->$prefixCode;
	if ($code == XRules::Present || $code == XRules::ProblemeRetardDepartAnticipe || $code == XRules::Ferie2 || $code == XRules::EcoleFormationIntegration || $code == XRules::EcoleFormationAlternance || $code == XRules::EcoleFormationEmploye) {
	    $mo = $data->montant;
	}

	return $mo;
    }

    /**
     * Calcul instruction de paie pour un groupe de planning
     * 
     * @param array $plannings
     * @param int $matricule
     * @return array
     */
    public function calculInstructionPaie($plannings = array(), $matricule = 0, $isSaved = false) {
	$plannings	 = $this->transformToArray($plannings);
	$data		 = array(
	    'matricule'					 => 0,
	    'anciennete'					 => 0.0,
	    'mensualite'					 => 0.0,
	    'total_heure'					 => 0.0,
	    'heure_comptabilise'				 => 0.0,
	    'heure_comptabilise_heure_supplementaire'	 => 0.0,
	    'ferie'						 => 0.0,
	    'dimanche'					 => 0.0,
	    'heure_negative'				 => 0.0,
	    'am1_jour'					 => 0.0,
	    'am1_heure'					 => 0.0,
	    'css'						 => 0.0,
	    'css_jour'					 => 0,
	    'at'						 => 0.0,
	    'cm'						 => 0.0,
	    'am2'						 => 0.0,
	    'cp_jour'					 => 0.0,
	    'cp_heure'					 => 0.0,
	    'repas'						 => 0,
	    'changement_contrat'				 => '',
	);
	if (!$isSaved) {
	    $data['regul'] = 0.0;
	    $data['entree_sortie_heure'] = 0.0;
	}
	$dayName	 = array(
	    'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche',
	);
	$planningObj	 = null;
	//$planningObj	 = $plannings->current();
	//\Zend\Debug\Debug::dump($plannings, 'Liste des plannings');
	foreach ($plannings as $planning) {
	    $planningObj = $planning;
	    foreach ($dayName as $day) {
		$dataDay	 = $this->calculateOneDay($planning, null, $day);
		$data['total_heure'] += $dataDay->tempsValeur;
		$data['ferie'] += $this->getFerie($planning, $day);
		$data['am1_jour'] += $this->countAM1($planning, $day);
		$data['am1_heure'] += $this->getAM1($planning, $day);
		$data['css'] += $this->getCSS($planning, $day);
		$data['css_jour'] += $this->getCSSJour($planning, $day);
		$data['at'] += $this->getAT($planning, $day);
		$data['cm'] += $this->GetCM($planning, $day);
		$data['am2'] += $this->getAM2($planning, $day);
		$data['cp_jour'] += $this->countCP($planning, $day);
		$data['cp_heure'] += $this->getCP($planning, $day);
		$data['heure_negative'] += $this->getNegativeHour($planning, $day);
		$dayRepas	 = $day . '_repas';
		$data['repas'] += (int) $planning->$dayRepas;
	    }

	    $data['dimanche'] += $this->getDimanches($planning);
	}

	$data['matricule'] = $matricule;

	//echo '<pre>Mensualite</pre>';
	$data['mensualite']				 = $this->getMensualite($matricule);
	//echo "<pre style='background: #ff1010; color: #ffffff;'>Calcul des heures complémentaire pour l'employe $matricule concerant le planning #$planning->id</pre>";
	$hc						 = $this->HeureComplementaire($plannings, $matricule);
	$data['hc_debug']				 = $hc['debug'];
	$data['heure_comptabilise']			 = $hc['value'];
	$hs						 = $this->HeureComplementaire25($plannings, $matricule);
	$data['hs_debug']				 = $hs['debug'];
	$data['heure_comptabilise_heure_supplementaire'] = $hs['value'];
	$periode					 = $this->getPeriode($plannings);
	//var_dump($plannings);

	if (!$isSaved) {
	    $data['regul'] = $this->getRegul($plannings, $matricule);
	    $data['entree_sortie_heure']			 = $this->getES($matricule, $periode);
	}
	// employé
	if ($planningObj) {
	    $tableEmploye	 = new EmployeTable($this->getAdapter());
	    $employe	 = $tableEmploye->get($planningObj->matricule);
	    $dateEntree	 = $employe->contrat_debut;
	    if ($dateEntree != '0000-00-00') {
		$lundi			 = $planningObj->lundi;
		// periode
		$tablePeriode		 = new PeriodeTable($this->getAdapter());
		$dataPeriode		 = $tablePeriode->getPeriodeByDate($lundi);
		$periode		 = new Periode($dataPeriode);
		$data['anciennete']	 = $this->getAnciennete($dateEntree, $periode->fin, true);
	    }
	    $data['changement_contrat'] = $this->changementContrat($plannings, $employe);
	}
	return $data;
    }

    /**
     * Valeur Férié
     *
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param string $day
     * @return real
     */
    private function getFerie(PlanningSemaine $planning, $day) {
	$dayCode = $day . '_code';
	$code	 = (int) $planning->$dayCode;
	if (/* $code == XRules::Ferie1 || */ $code == XRules::Ferie2 /* || $code == XRules::Ferie3 */) {
	    $data = $this->calculateOneDay($planning, $planning->getTemplate(), $day);
	    return $data->tempsValeur;
	}
	else {
	    return 0.0;
	}
    }

    /**
     * Arrêt Maladie 1
     *
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param string $day
     * @return real
     */
    private function getAM1(PlanningSemaine $planning, $day) {
	$dayCode = $day . '_code';
	$code	 = (int) $planning->$dayCode;
	if ($code == XRules::ArretMaladie1) {
	    $data = $this->calculateOneDay($planning, null, $day);

	    return $data->tempsValeur;
	}
	else {
	    return 0.0;
	}
    }

    /**
     * Compter les jours AM1
     *
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param string $day
     * @return int
     */
    private function countAM1(PlanningSemaine $planning, $day) {
	$dayCode = $day . '_code';
	$code	 = (int) $planning->$dayCode;
	if ($code == XRules::ArretMaladie1) {
	    return 1;
	}
	else {
	    return 0;
	}
    }

    /**
     * Congé Sans Solde
     *
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param string $day
     * @return real
     */
    public function getCSS(PlanningSemaine $planning, $day) {
	$dayCode = $day . '_code';
	$code	 = (int) $planning->$dayCode;
	if ($code == XRules::CongeSansSolde) {
	    $data = $this->calculateOneDay($planning, null, $day);
	    return $data->tempsValeur;
	}
	else {
	    return 0.0;
	}
    }

    /**
     * Congé Sans Solde Jour
     *
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param string $day
     * @return int
     */
    public function getCSSJour(PlanningSemaine $planning, $day) {
	$dayCode = $day . '_code';
	$code	 = (int) $planning->$dayCode;
	if ($code == XRules::CongeSansSolde) {
	    return 1;
	}
	else {
	    return 0;
	}
    }

    /**
     * Accident de travail
     * 
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param string $day
     * @return real
     */
    public function getAT(PlanningSemaine $planning, $day) {
	$dayCode = $day . '_code';
	$code	 = (int) $planning->$dayCode;
	if ($code == XRules::AccidentTravail) {
	    $data = $this->calculateOneDay($planning, null, $day);

	    return $data->tempsValeur;
	}
	else {
	    return 0.0;
	}
    }

    /**
     * Congé de Maternité, Congé de Maternité Père
     * 
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param string $day
     * @return real
     */
    public function getCM(PlanningSemaine $planning, $day) {
	$dayCode = $day . '_code';
	$code	 = (int) $planning->$dayCode;
	if ($code == XRules::CongeMaternite || $code == XRules::CongeMaternitePere) {
	    $data = $this->calculateOneDay($planning, null, $day);

	    return $data->tempsValeur;
	}
	else {
	    return 0.0;
	}
    }

    /**
     * Arrêt Maladie 2
     *
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param string $day
     * @return real
     */
    private function getAM2(PlanningSemaine $planning, $day) {
	$dayCode = $day . '_code';
	$code	 = (int) $planning->$dayCode;
	if ($code == XRules::ArretMaladie2) {
	    $data = $this->calculateOneDay($planning, null, $day);

	    return $data->tempsValeur;
	}
	else {
	    return 0.0;
	}
    }

    /**
     * Compter congé Payés
     *
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param string $day
     * @return int
     */
    private function countCP(PlanningSemaine $planning, $day) {
	$dayCode = $day . '_code';
	$code	 = (int) $planning->$dayCode;
	if ($code == XRules::CongePaye || $code == XRules::CongePayeExceptionnel) {
	    return 1;
	}
	else {
	    return 0;
	}
    }

    /**
     * Arrêt Maladie 1
     *
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param string $day
     * @return real
     */
    private function getCP(PlanningSemaine $planning, $day) {
	$dayCode = $day . '_code';
	$code	 = (int) $planning->$dayCode;
	if ($code == XRules::CongePaye || $code == XRules::CongePayeExceptionnel) {
	    $data = $this->calculateOneDay($planning, null, $day);

	    return $data->tempsValeur;
	}
	else {
	    return 0.0;
	}
    }

    /**
     * Heure négative
     * 
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param string $day
     * @return real
     */
    private function getNegativeHour(PlanningSemaine $planning, $day) {
	$dayCode = $day . '_code';
	$code	 = (int) $planning->$dayCode;
	if ($code == XRules::ProblemeRetardDepartAnticipe || $code == XRules::Absent) {
	    $data	 = $this->calculateOneDay($planning, null, $day);
	    $value	 = 0.0;
	    // Le calcul de l'absence est dans le retard
	    if ($data->retard) {
		$value += RHDateTime::toFloat($data->tempsRetard);
	    }
	    if ($data->anticipe) {
		$value += RHDateTime::toFloat($data->tempsAnticipe);
	    }

	    return $value;
	}
	else {
	    return 0.0;
	}
    }

    /**
     * Ancienneté exprimé en nombre à virgule
     * 
     * @param string $dateEntree
     * @param string $dateRef
     * @param boolean $aff
     * @return string|real
     */
    public function getAnciennete($dateEntree, $dateRef = null, $aff = true) {
	if (is_null($dateRef)) {
	    $dateRef = date('Y-m-d');
	}
	$entree		 = new \DateTime($dateEntree);
	$ref		 = new \DateTime($dateRef);
	$diff		 = date_diff($ref, $entree);
	$anciennete	 = ($diff->invert) ? (($diff->y * 365) + ($diff->m * 12) + $diff->d) / 365 : 0.0;

	if ($aff) {
	    return number_format($anciennete, 2, ',', ' ');
	}
	else {
	    return round($anciennete, 2);
	}
    }

    /**
     * Dimanches
     * 
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @return float
     */
    public function getDimanches(PlanningSemaine $planning) {
	$data = $this->calculateOneDay($planning, $planning->getTemplate(), 'dimanche');

	return $data->tempsValeur;
    }

    /**
     * Indique si la pause est valable ou non
     *
     * @param string $entree
     * @param string $sortie
     * @param string $refTime
     * @return boolean
     */
    public function isPause($entree, $sortie, $refTime = '05:00') {
	$diff	 = RHDateTime::diffHours($sortie, $entree);
	$time	 = new RHDateTime();
	$time->setTime();
	$time->addHours($diff);
	$ref	 = new RHDateTime();
	$ref->setTime($refTime);
	if ($time->isTimeGT($ref) || $time->isTimeEqual($ref)) {
	    return true;
	}

	return false;
    }

    /**
     * Indique si le Repas est valable ou non
     *
     * @param string $entree
     * @param string $sortie
     * @param string $refDebut
     * @param string $refFin
     * @return boolean
     */
    public function isRepas($entree, $sortie, $refDebut = '12:00', $refFin = '14:00') {
	$in	 = new RHDateTime();
	$out	 = new RHDateTime();
	$debut	 = new RHDateTime();
	$fin	 = new RHDateTime();
	$in->setTime($entree);
	$out->setTime($sortie);
	$debut->setTime($refDebut);
	$fin->setTime($refFin);
	if ($debut->isTimeBetween($in, $out) || $fin->isTimeBetween($in, $out)) {
	    return true;
	}

	return false;
    }

    /**
     * Calcul d'une journée
     * 
     * @param int $matricule
     * @param int $code
     * @param string $entree
     * @param string $sortie
     * @param int $pause
     * @param int $repas
     * @param string $prefix
     * @return XData
     */
    public function oneDayCalcul($matricule, $code, $entree, $sortie, $pause, $repas, $prefix) {
	// nom des variables
	$dayCode		 = $prefix . '_code';
	$dayEntree		 = $prefix . '_entree';
	$daySortie		 = $prefix . '_sortie';
	$dayPause		 = $prefix . '_pause';
	$dayRepas		 = $prefix . '_repas';
	$planning		 = new PlanningSemaine($this->adapter);
	$planning->matricule	 = $matricule;
	$planning->$dayCode	 = $code;
	$planning->$dayEntree	 = $entree;
	$planning->$daySortie	 = $sortie;
	$planning->$dayPause	 = $pause;
	$planning->$dayRepas	 = $repas;
	$data			 = $this->calculateOneDay($planning, NULL, $prefix);

	return $data;
    }

    /**
     * Récupérer le prorata
     * 
     * @param string $heurePrevues
     * @param string $jour
     * @return string
     */
    public function prorataHeurePrevues($heurePrevues, $jour) {
	$dayName	 = array('lundi' => 1, 'mardi' => 2, 'mercredi' => 3, 'jeudi' => 4, 'vendredi' => 5);
	$jourTravaille	 = isset($dayName[$jour]) ? 5 - $dayName[$jour] : 0;
	$prorata	 = RHDateTime::toFloat($heurePrevues) * ($jourTravaille / 5);
	//\Zend\Debug\Debug::dump($prorata, "Prorata en décimal pour le calcul $heurePrevues / $jourTravaille jour(s)");
	$result		 = array(
	    'float'	 => $prorata,
	    'time'	 => RHDateTime::toTime($prorata),
	);
	return $result;
    }

    /**
     * Calcul du salaire brute
     * 
     * @param \RHX\Model\Object\InstructionPaie $inst
     * @param array $plannings
     * @param string $date
     * @return array
     */
    public function calculSalaireBrute(InstructionPaie $inst, $plannings, $date = null) {
	$date = is_null($date) ? date('Y-m-d') : $date;
	$tableEmploye	 = new EmployeTable($this->adapter);
	$employe	 = $tableEmploye->get($inst->matricule);
	$dataCP		 = $employe->getDataCP($date);
	$travail = $this->getHeureTravaille($plannings);
	$salaire1 = (($inst->mensualite + $inst->heure_comptabilise + ($inst->heure_comptabilise_heure_supplementaire * 1.25) + ($inst->heure_supplementaire * 1.5) + $inst->ferie + $inst->dimanches - abs($inst->heure_negative) - abs($inst->heure_module_css) - abs($inst->entree_sortie_heure)) * $dataCP['taux']) + $inst->prime_montant + $inst->prime_montant_hors_cp + $inst->hors_temps_travail_montant + ($inst->repas * 3.44) + $inst->mutuelle + $inst->vehicule + $inst->ijss_brute_montant;
	$salaire2 = 0.0;
	if((int)$inst->entree_sortie_heure > 0){
	    $salaire2 = (($travail - $inst->heure_comptabilise_heure_supplementaire - $inst->heure_supplementaire) * $dataCP['taux'] /* $dataCP['coef']*/);
	}
	//echo "<pre>ES : $inst->entree_sortie_heure, Salaire 1 : $salaire1, Salaire 2 : $salaire2</pre>";
	return ($salaire1 > $salaire2) ? array('salaire' => $salaire1, 'mode' => 1) : array('salaire' => $salaire2, 'mode' => 2);
    }
    
    /**
     * Heures travaillées
     * 
     * @param array $plannings
     * @return real
     */
    public function getHeureTravaille($plannings){
	$module = 0.0;
	foreach($plannings as $p){
	    $module += RHDateTime::toFloat($this->getHeuresModulees($p)->totalHours());
	}
	return $module;
    }

    /**
     * Calcul du salaire brute propre au synthese
     * 
     * @param \RHX\Model\Object\InstructionPaie $inst
     * @return real
     */
    public function calculSalaireBruteSynthese(InstructionPaie $inst) {
	$tableEmploye	 = new EmployeTable($this->adapter);
	$employe	 = $tableEmploye->get($inst->matricule);

	$dataCP	 = $employe->getDataCP();
	$salaire = (($inst->mensualite + $inst->heure_comptabilise + ($inst->heure_comptabilise_heure_supplementaire * 1.25) + ($inst->heure_supplementaire * 1.5) + $inst->ferie + $inst->dimanches - abs($inst->heure_negative) - abs($inst->heure_module_css) - abs($inst->entree_sortie_heure)) * $dataCP['taux']) + $inst->prime_montant + $inst->prime_montant_hors_cp + $inst->hors_temps_travail_montant + ($inst->repas * 3.44) + $inst->mutuelle + $inst->vehicule + $inst->ijss_brute_montant;

	$absence = 0.0;
	$val1	 = ($inst->mensualite + $inst->heure_comptabilise - $absence + $inst->heure_module_m1 ) * $dataCP['taux'];

	$heureRegM1_sup	 = 0.0;
	$val2		 = ($inst->heure_comptabilise_heure_supplementaire + $heureRegM1_sup) * $dataCP['taux'] * 1.25;

	$indCp_reg	 = $inst->heure_module_m1;
	$val3		 = ($inst->prime_montant + $indCp_reg + (3.49 * $inst->repas));

	$salaire_synth = $val1 + $val2 + $val3;

	return $salaire;
	//return $salaire_synth;
    }

    /**
     * Mensualité d'un employé
     * hedbo * 52/12
     * 
     * @param int $matricule
     * @param int $arrondi
     * @return float
     */
    public function getMensualite($matricule, $round = 2) {
	$tableEmploye	 = new EmployeTable($this->getAdapter());
	$employe	 = $tableEmploye->get($matricule);
	$dataCP		 = $employe->getDataCP();
	//echo '<pre>' .($dataCP['hebdo'] * 52) / 12 .'</pre>';
	return round(($dataCP['hebdo'] * 52) / 12, $round);
    }

    /**
     * Calcul des heures complémentaires
     * 
     * @param PlanningSemaine $plannings
     * @param int $matricule
     * @return real
     */
    public function HeureComplementaire($plannings, $matricule, $coef = 0.1) {
	$hc		 = 0.0;
	$debug		 = '';
	$heureModuleLabo = $this->heureModuleLabo($plannings);
	$debug .= "Heure Labo = $heureModuleLabo";
	/* SI(DI11=0;
	  SI(BU11>0;
	  SI(CR11<35;
	  SI(BU11>=(BQ11*0,1);
	  (BQ11*0,1);
	  SINON
	  BU11);
	  SINON
	  0);
	  SINON
	  0);
	  SINON
	  0) */
	$date		 = isset($plannings[0]) ? $plannings[0]->lundi : null;
	$hebdo		 = $this->getHebdo($matricule, $date);
	$soldePP	 = $this->soldePP($plannings);
	$totalHebdo	 = $this->totalHeureHebdo($plannings, $matricule);
	$debug .= "Heure Labo = $heureModuleLabo";
	$debug .= ", SoldePP = $soldePP";
	$debug .= ", hebdo = $hebdo";
	$debug .= ", Total Heure Hebdo $totalHebdo";
	$total		 = ($totalHebdo * 0.1);
	$debug .= ", Total Heure Hedbo = $total ($coef)";
	if ($heureModuleLabo == 0) {
	    if ($soldePP > 0) {
		if ($hebdo < 35) {
		    if ($soldePP >= ($totalHebdo * $coef)) {
			$hc = ($totalHebdo * $coef);
		    }
		    else {
			$hc = $soldePP;
		    }
		}
		else {
		    $hc = 0.0;
		}
	    }
	    else {
		$hc = 0.0;
	    }
	}
	else {
	    $hc = 0.0;
	}
	$debug .= ", HC = $hc";
	return array(
	    'value'	 => $hc,
	    'debug'	 => $debug,
	);
    }

    public function HeureComplementaire25($plannings, $matricule, $coef = 0.1) {
	/**
	  SI(DI11=0;
	  SI(BU11>0;
	  SI(CR11<35;
	  SI(BU11>(BQ11*0,1);
	  (BU11)-(BQ11*0,1);
	  SINON
	  0);
	  SINON
	  BU11);
	  SINON
	  0);
	  SINON
	  0)
	 */
	$hc		 = 0.0;
	$debug		 = '';
	$heureModuleLabo = $this->heureModuleLabo($plannings);
	$debug .= "Labo = $heureModuleLabo";
	if ($heureModuleLabo == 0) {
	    $soldePP = $this->soldePP($plannings);
	    $debug .= ", Solde PP = $soldePP";
	    if ($soldePP > 0) {
		$date	 = isset($plannings[0]) ? $plannings[0]->lundi : null;
		$hebdo	 = $this->getHebdo($matricule, $date);
		$debug .= ", Hebdo = $hebdo";
		$total	 = $this->totalHeureHebdo($plannings, $matricule) * $coef;
		$debug .= ", Total Hebdo $total ($coef)";
		if ($hebdo < 35.00) {
		    $hc = ($soldePP > $total) ? $soldePP - $total : 0.0;
		    $debug .= ", Diff = " . ($soldePP - $total);
		}
		else {
		    $hc = $soldePP;
		}
	    }
	}
	$debug .= ", HS = $hc";
	return array(
	    'value'	 => $hc,
	    'debug'	 => $debug,
	);
    }

    /*
     * recupérer la somme des heures modulée de semaine
     * 
     * @param PlanningSemaine $plannings
     */

    public function getSumHeuresModulees($plannings = array()) {
	$sum = 0.0;
	foreach ($plannings as $ps):
	    $modulee = RHDateTime::toFloat($this->getHeuresModulees($ps)->totalHours());
	    $sum += $modulee;
	endforeach;

	return $sum;
    }

    /**
     * Heure Modulé Labo
     * 
     * @param PlanningSemaine $plannings
     * @return real
     */
    public function heureModuleLabo($plannings) {
	return 0.0;
    }

    /**
     * Solde PP
     * 
     * @param PlanningSemaine $plannings
     * @return real
     */
    public function soldePP($plannings) {
	$reportM1	 = $this->reportM1($plannings);
	$reportP1	 = $this->reportP1($plannings);
	$diff		 = $this->diff($plannings);
	$css		 = $this->css($plannings);
	$solde		 = $reportM1 + $diff + $reportP1 - $css;
	//echo "<pre>Solde = $reportM1 (reportM1) + $diff (Diff) + $reportP1 (ReportP1) - $css (Css) = $solde</pre>";
	return $solde;
    }

    /**
     * Heure hebdomadaire
     * 
     * @param int $matricule
     * @param string $date
     * @return real
     */
    public function getHebdo($matricule, $date = null) {
	$tableEmploye	 = new EmployeTable($this->getAdapter());
	$employe	 = $tableEmploye->get($matricule);
	return $employe->getHoraireHebdo(false, $date);
    }

    /**
     * Total des heures hebdomadaire
     * 
     * @param PlanningSemaine $plannings
     * @param int $matricule
     * @return real
     */
    public function totalHeureHebdo($plannings, $matricule) {
	$hebdo = 0.0;
	foreach ($plannings as $planning) {
	    //$hebdo += $this->getHebdo($matricule, $planning->lundi);
	    $hebdo += $this->getHebdom($planning);
	}
	return $hebdo;
    }

    /**
     * Report PP M+1
     * 
     * @param PlanningSemaine $plannings
     * @return real
     */
    public function reportP1($plannings) {
	$report = 0.0;
	return $report;
    }

    /**
     * Report PP M-1
     * 
     * @param PlanningSemaine $plannings
     * @return real
     */
    public function reportM1($plannings) {
	$report = 0.0;
	return $report;
    }

    /**
     * Différence des heures modulées et des heures du contrat
     * 
     * @param PlanningSemaine $plannings
     * @return real
     */
    public function diff($plannings) {
	$module	 = 0.0;
	$hebdo	 = 0.0;
	foreach ($plannings as $planning) {
	    $module += RHDateTime::toFloat($this->getHeuresModulees($planning)->totalHours());
	    $hebdo += $this->getHebdom($planning);
	}
	$diff = $module - $hebdo;
	//echo "<pre>Diff = $module (Module) - $hebdo (Hebdo) = $diff</pre>";
	return $diff;
    }

    /**
     * Heure CSS des plannings
     * 
     * @param PlanningSemaine $plannings
     * @return real
     */
    public function css($plannings) {
	$css	 = 0.0;
	$dayName = array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche');
	foreach ($plannings as $planning) {
	    foreach ($dayName as $day) {
		$css += $this->getCSS($planning, $day);
	    }
	}
	return $css;
    }

    /**
     * 
     * @param mixed $plannings
     * @return array
     */
    private function transformToArray($plannings) {
	if (!is_array($plannings)) {
	    $array = array();
	    foreach ($plannings as $p) {
		$array[] = $p;
	    }
	    return $array;
	}
	return $plannings;
    }

    /**
     * Détermine s'il y a eu changement de contrat durant les plannings
     * 
     * @param PlanningSemaine $plannings
     * @param Employe $employe
     * @return string
     */
    private function changementContrat($plannings, $employe) {
	$value	 = '';
	$dayName = array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche');
	if ((int) $employe->ancien != 0) {
	    foreach ($plannings as $planning) {
		$debut = new RHDateTime($employe->contrat_debut);
		foreach ($dayName as $day) {
		    $date = new RHDateTime($planning->$day);
		    if ($date->isEqual($debut)) {
			$value = 'Oui (' . $date->date('m/d/Y') . ')';
		    }
		}
	    }
	}
	return $value;
    }

    /**
     * Récupération des horaires hebdomadaires à partir du planning semaine
     * 
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @return real
     */
    private function getHebdom(PlanningSemaine $planning) {
	$es = $this->countCode($planning, XRules::EntreeSortie);
	if ($es >= 5) {
	    return 0.0;
	}
	elseif ($es > 0) {
	    $workDays	 = 5 - $es;
	    $hebdo		 = $this->getHebdo($planning->matricule, $planning->lundi);
	    return round($hebdo / $workDays, 2);
	}
	else {
	    return $this->getHebdo($planning->matricule, $planning->lundi);
	}
    }

    /**
     * Compter les occurences d'un code activité dans un planning semaine
     * 
     * @param \RHX\Model\Object\PlanningSemaine $planning
     * @param int $code
     * @return int
     */
    private function countCode(PlanningSemaine $planning, $code = XRules::Present) {
	$dayName = array('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche');
	$count	 = 0;
	foreach ($dayName as $day) {
	    $dayCode = $day . '_code';
	    if ($code == (int) $planning->$dayCode) {
		$count++;
	    }
	}
	return $count;
    }

    /**
     * Régulation
     * 
     * @param array $plannings
     * @return real
     */
    public function getRegul($plannings, $matricule) {
	$module		 = $this->getModule($plannings);
	$planning	 = $this->getPlanningFromNumber($plannings, 1);
	$hebdo		 = 0.0;
	if (is_null($planning)) {
	    $hebdo = $this->getHebdo($matricule);
	}
	else {
	    $hebdo = $this->getHebdom($planning);
	}
	$report = $this->reportM1($plannings);
	return ($report + $module) - $hebdo;
    }

    /**
     * Nombre d'heures travaillées
     * Nombre d'heures modulées
     * 
     * @param array $plannings
     * @return float
     */
    private function getModule($plannings) {
	$planning = $this->getPlanningFromNumber($plannings, 1);
	if (is_null($planning)) {
	    return 0.0;
	}
	$dataWeek	 = $this->calculateOneWeek($planning, $planning->getTemplate(), $planning->lundi);
	//var_dump($dataWeek);
	$module		 = RHDateTime::toFloat($dataWeek['heureTravaille']);
	return $module;
    }

    /**
     * Planning Semaine
     * 
     * @param array $plannings
     * @param int $number
     * @return PlanningSemaine
     */
    private function getPlanningFromNumber($plannings, $number = 0) {
	return isset($plannings[$number]) ? $plannings[$number] : null;
    }

    /**
     * Récupération des Heures ES
     * 
     * @param int $matricule
     * @param Periode $periode
     * @return float
     */
    public function getES($matricule, $periode) {
	$manager = new \RHX\Model\Manager\InstructionManager($this->getAdapter());
	return $manager->getES($matricule, $periode);
    }

    /**
     * Récupération de la période
     * 
     * @param type $plannings
     * @return \RHX\Model\Object\Periode
     */
    public function getPeriode($plannings) {
	$periode = null;
	$table	 = new PeriodeTable($this->getAdapter());
	foreach ($plannings as $plan) {
	    $periode = $table->getPeriode($plan->lundi);
	    break;
	}
	return $periode;
    }

}
